package com.ruoyi.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ruoyi.common.PageResult;
import com.ruoyi.common.Result;
import com.ruoyi.common.config.FileStorageProperties;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.exception.FileErrorException;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.domain.dto.FileDTO;
import com.ruoyi.domain.pojo.FilePO;
import com.ruoyi.domain.vo.FileVO;
import com.ruoyi.mapper.FileMapper;
import com.ruoyi.service.FileService;
import com.ruoyi.thread.processThread;
import com.ruoyi.utils.VideoUtil;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.UUID;

/**
 * @Classname FileServiceImpl
 * @Description TODO
 * @Date 2025/3/19 14:01
 * @Created by xxx
 */
@Slf4j
@Service
@Data
@RequiredArgsConstructor
public class FileServiceImpl implements FileService {

    private final FileStorageProperties fileStorageProperties;
    private final FileMapper fileMapper;
    private ThreadPoolTaskExecutor executor = SpringUtils.getBean("threadPoolTaskExecutor");

    private static String getDuration(Path savePath) {
        String duration;
        long time = 0;
        try {
            time = VideoUtil.getDuration(savePath.toAbsolutePath().toString());
        } catch (IOException e) {
            throw new FileErrorException("获取文件时长失败");
        }
        if (time >= 3600) duration = String.format("%02d:%02d:%02d", time / 3600, time / 60 % 60, time % 60);
        else {
            duration = String.format("%02d:%02d", time / 60, time % 60);
        }
        return duration;
    }

    private String getBaseUrl() {
        //获取当前ip和端口
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        InetAddress address = null;
        try {
            address = InetAddress.getLocalHost();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        String baseUrl = "http://" + address.getHostAddress() + ":" + fileStorageProperties.getUsePort();
        return baseUrl;
    }

    @Override
    public boolean upload(FileDTO fileDTO) {
        Integer type = fileDTO.getType();
        Long createBy = fileDTO.getCreateBy();
        String title = fileDTO.getTitle();
        MultipartFile file = fileDTO.getFile();
        //获取当前ip和端口
        Path saveDir = Paths.get(fileStorageProperties.getUploadDir(), createBy.toString());
        String url = "/files/" + createBy;
        if (Objects.equals(type, Constants.TEXT)) {
            //文本文件
            saveDir = saveDir.resolve(Constants.TEXT_DIR);
            url = url + "/" + Constants.TEXT_DIR;
        } else if (Objects.equals(type, Constants.AUDIO)) {
            //语音文件
            saveDir = saveDir.resolve(Constants.AUDIO_DIR);
            url = url + "/" + Constants.AUDIO_DIR;
        } else {
            throw new FileErrorException("文件类型不支持");
        }
        UUID uuid = UUID.randomUUID();
        String suffix = Objects.requireNonNull(file.getOriginalFilename()).substring(file.getOriginalFilename().lastIndexOf("."));
        Path savePath = saveDir.resolve(uuid.toString() + suffix);
        url = url + "/" + uuid + suffix;
        log.info("url{}", url);
        //文件夹不存在，先创建文件夹
        try {
            Files.createDirectories(saveDir);
        } catch (IOException e) {
            throw new FileErrorException("文件上传失败");
        }
        //保存文件
        try {
            file.transferTo(savePath);
        } catch (IOException e) {
            throw new FileErrorException("服务器文件保存失败");
        }
        String duration = "";
        if (Objects.equals(type, Constants.AUDIO)) duration = getDuration(savePath);
        FilePO filePO = new FilePO();
        BeanUtils.copyProperties(fileDTO, filePO);
        filePO.setFilePath(savePath.toString());
        filePO.setDuration(duration);
        filePO.setStatus(0);
        filePO.setCollected(fileDTO.getCollect());
        if (filePO.getCollected() != null && fileDTO.getCollect() == 1) {
            filePO.setCollectTime(LocalDateTime.now());
        }
        filePO.setDeleted(0);
        filePO.setUrl(url);
        filePO.setUpdateTime(LocalDateTime.now());
        filePO.setStartTime(fileDTO.getStartTime());
        filePO.setEndTime(fileDTO.getEndTime());
        filePO.setMeetingName(fileDTO.getMeetingName());
        filePO.setMeetingPlace(fileDTO.getMeetingPlace());
        filePO.setTemplateId(fileDTO.getTemplateId());
        fileMapper.insert(filePO);
        executor.execute(new processThread(filePO, fileMapper, fileStorageProperties, uuid, getBaseUrl()));
        return true;
    }

    @Override
    public PageResult list(FileDTO fileDTO) {
        Integer category = fileDTO.getCategory();
        PageHelper.startPage(fileDTO.getPage(), fileDTO.getPageSize());
        FilePO filePO = new FilePO();
        BeanUtils.copyProperties(fileDTO, filePO);
        List<FileVO> fileVOS = null;
        if (category == 0) {
            if (filePO.getPastDay() == null) {
                filePO.setPastDay(3);
            }
            filePO.setDeleted(0);
            fileVOS = fileMapper.selectListWithPastDay(filePO);
        } else if (category == 1) {
            filePO.setPastDay(null);
            filePO.setDeleted(0);
            fileVOS = fileMapper.selectListWithMyFile(filePO);
        } else if (category == 2) {
            filePO.setPastDay(null);
            filePO.setCollected(1);
            filePO.setDeleted(0);
            fileVOS = fileMapper.selectListWithCollect(filePO);
        } else if (category == 3) {
            filePO.setPastDay(null);
            filePO.setDeleted(1);
            fileVOS = fileMapper.selectListWithDelete(filePO);
        }
        PageInfo<FileVO> pageInfo = new PageInfo<>(fileVOS);
        PageResult pageResult = new PageResult(pageInfo.getTotal(), pageInfo.getList());
        return pageResult;
    }

    @Override
    public boolean collections(Integer id, Long userId) {
        FilePO filePO = FilePO.builder()
                .id(id)
                .createBy(userId)
                .build();
        Integer before = fileMapper.getCollectStatus(filePO);
        if (before == 0) {
            filePO.setCollectTime(LocalDateTime.now());
        }
        filePO.setUpdateTime(LocalDateTime.now());
        fileMapper.updateCollect(filePO);
        Integer after = fileMapper.getCollectStatus(filePO);
        return !Objects.equals(before, after);
    }

    @Override
    public boolean delete(Integer id, Long userId) {
        FilePO filePO = FilePO.builder()
                .id(id)
                .createBy(userId)
                .build();
        Integer before = fileMapper.getDeleteStatus(filePO);
        if (before == 0) {
            filePO.setDeleteTime(LocalDateTime.now());
        }
        filePO.setUpdateTime(LocalDateTime.now());
        fileMapper.updateDelete(filePO);
        Integer after = fileMapper.getDeleteStatus(filePO);
        return !Objects.equals(before, after);
    }

    @Override
    public boolean readDelete(Integer id, Long userId) {
        FilePO filePO = FilePO.builder()
                .id(id)
                .createBy(userId)
                .build();
        Integer before = fileMapper.getDeleteStatus(filePO);
        if (!Objects.equals(before, 1)) {
            return false;
        }
        FilePO filePO1 = fileMapper.selectByIdAndCreateBy(filePO);
        Path path = null, transPath = null, minutesPath = null;
        if (filePO1.getFilePath() != null) path = Paths.get(filePO1.getFilePath());
        if (filePO1.getTransPath() != null) transPath = Paths.get(filePO1.getTransPath());
        if (filePO1.getMinutesPath() != null) minutesPath = Paths.get(filePO1.getMinutesPath());
        try {
            if (path != null && Files.exists(path)) Files.delete(path);
            if (transPath != null && transPath.toFile().exists()) Files.delete(transPath);
            if (minutesPath != null && minutesPath.toFile().exists()) Files.delete(minutesPath);
        } catch (IOException e) {
            throw new FileErrorException("文件删除失败");
        }

        fileMapper.realDelete(filePO);
        return true;
    }

    @Override
    public boolean clean(Long userId) {
        FilePO filePO = FilePO.builder()
                .deleted(1)
                .createBy(userId)
                .build();
        List<String> filePaths = fileMapper.selectFilePathList(filePO);
        for (String filePath : filePaths) {
            Path path = Paths.get(filePath);
            if (Files.exists(path)) {
                try {
                    Files.delete(path);
                } catch (IOException e) {
                    throw new FileErrorException("文件删除失败");
                }
            }
        }
        fileMapper.clean(filePO);
        return true;
    }

    @Override
    public FilePO download(Integer id, Long userId) {
        FilePO filePO1 = FilePO.builder()
                .id(id)
                .createBy(userId)
                .build();
        FilePO filePO = fileMapper.selectByIdAndCreateBy(filePO1);
        return filePO;
    }

    @Override
    public Result getDetail(Integer id, Long userId) {
        FilePO filePO1 = FilePO.builder()
                .id(id)
                .createBy(userId)
                .build();
        FilePO filePO = fileMapper.selectByIdAndCreateBy(filePO1);
        String baseUrl = getBaseUrl();
        String minutesUrl = getEditUrl(Paths.get(filePO.getMinutesPath()), Constants.MINUTES_DIR, filePO);
        String fileUrl = null;
        if (Objects.equals(filePO.getType(), Constants.TEXT)) {
            fileUrl = getEditUrl(Paths.get(filePO.getFilePath()), Constants.TEXT_DIR, filePO);
        } else {
            fileUrl = getEditUrl(Paths.get(filePO.getTransPath()), Constants.TRANS_DIR, filePO);
        }
        FileVO fileVO = FileVO.builder()
                .title(filePO.getTitle())
                .url(filePO.getUrl())
                .content(filePO.getContent())
                .minutes(filePO.getMinutes())
                .type(filePO.getType())
                .startTime(filePO.getStartTime())
                .endTime(filePO.getEndTime())
                .meetingName(filePO.getMeetingName())
                .meetingPlace(filePO.getMeetingPlace())
                .templateId(filePO.getTemplateId())
                .fileUrl(fileUrl)
                .minutesUrl(minutesUrl)
                .summary(filePO.getSummary())
                .build();
        return Result.success(fileVO);
    }

    private String getEditUrl(Path filePath, String type, FilePO filePO) {
        String baseUrl = getBaseUrl();
        baseUrl = baseUrl + "/files/" + filePO.getCreateBy().toString() + "/" + type + "/" + filePath.getFileName();
        //log.info("获取文件url：{}", baseUrl);
        try {
            baseUrl = URLEncoder.encode(baseUrl, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            log.info("URL编码失败：{}", e.getMessage());
        }
        String fileName = filePath.getFileName().toString();
        String editUrl = "http://" + fileStorageProperties.getOnlineUrl() +
                "/onlineEdit?" +
                "url=" +
                baseUrl +
                "&fileName=" +
                fileName +
                "&userId=" +
                filePO.getCreateBy().toString() +
                "&type=" +
                type;
        log.info("获取文件url：{}", editUrl);
        return editUrl;
    }

    @Override
    public Result save(Integer id, Long userId, String minutes) {
        //minutes = minutes.replaceAll(" ", "&nbsp;");
//        if (minutes == null) {
//            minutes = "";
//        }
//        FilePO filePO1 = FilePO.builder()
//                .id(id)
//                .createBy(userId)
//                .minutes(minutes)
//                .updateTime(LocalDateTime.now())
//                .build();
//        fileMapper.update(filePO1);
//        FilePO filePO = fileMapper.selectByIdAndCreateBy(filePO1);
//        File file = new File(filePO.getMinutesPath());
//        //写入文件并覆盖原文件
//        try {
//            //Files.write(file.toPath(), minutes.getBytes());
//            //WordToHtml.convertHTMLToWord(minutes, filePO.getMinutesPath());
//            //HtmlToDocxConverter.convertHtmlToDocx(minutes, filePO.getMinutesPath());
//            HtmlToWord.convertHtmlToDocx(minutes, filePO.getMinutesPath());
//        } catch (Exception e) {
//            return Result.error("保存文件失败");
//        }
        return Result.success();
    }

    @Override
    public Result redo(Integer id, Long userId) {
        FilePO filePO1 = FilePO.builder()
                .id(id)
                .createBy(userId)
                .build();
        FilePO filePO = fileMapper.selectByIdAndCreateBy(filePO1);
        if (filePO == null) {
            return Result.error("文件不存在");
        }
        if (filePO.getStatus() != -1 && filePO.getStatus() != -2) {
            return Result.error("文件正在处理");
        }
        log.info(filePO.toString());
        File file = new File(filePO.getFilePath());
        MultipartFile multipartFile = null;
        try {
            multipartFile = new MockMultipartFile("file", file.getName(), null, new FileInputStream(file));
        } catch (IOException e) {
            return Result.error("本地文件丢失");
        }
        FileDTO fileDTO = FileDTO.builder()
                .title(filePO.getTitle())
                .type(filePO.getType())
                .file(multipartFile)
                .createBy(userId)
                .collect(0)
                .createTime(LocalDateTime.now())
                .startTime(filePO.getStartTime())
                .endTime(filePO.getEndTime())
                .meetingName(filePO.getMeetingName())
                .meetingPlace(filePO.getMeetingPlace())
                .templateId(filePO.getTemplateId())
                .build();
        boolean upload = upload(fileDTO);
        delete(id, userId);
        readDelete(id, userId);
        return upload ? Result.success() : Result.error("文件处理失败");
    }
}
